# -*- coding: utf-8 -*-
"""
Created on Sun Feb 11 19:31:26 2018

@author: Allen
"""

import numpy as np
from math import sqrt
from collections import Counter
from .metrics import accuracy_score

class KNNClassifier( object ):
    
    def __init__( self, k ):
        '''
        初始化KNN
        k 为 近邻的个数
        '''
        self.k = k
        self._X_train = None
        self._y_train = None
        
    def fit( self, X_train, y_train ):
        '''
        获取训练集和标签
        '''
        self._X_train = X_train
        self._y_train = y_train
        return
    
    def predict( self, X_predict ):
        '''
        对预测结果进行返回
        X_predict 必须是一个矩阵
        '''
        y_predict = [ self._predict( x ) for x in X_predict ]
        return np.array( y_predict )
    
    def _predict( self, x ):
        '''
         算法步骤：
         1、计算到每一个点的欧氏距离
         2、排序找到最近的k个点
         3、计算近邻点中，占比最多的分类
         4、该分类就是最终结果
        '''
        distances = [ sqrt(np.sum((x_train - x)**2)) for x_train in self._X_train ]
        nearest_index = np.argsort( distances ) 
        top_K = self._y_train[nearest_index[ :self.k ]].tolist()
        votes = Counter( top_K )    
        return votes.most_common(1)[0][0]
    
    def score( self, X_test, y_true ):
        '''
        不返回预测值，直接返回准确率accuracy
        '''
        y_predict = self.predict( X_test )
        return accuracy_score( y_true, y_predict )
    
if __name__ == "__main__":
    raw_data_X = [
        [3.393533211,2.331273381],
        [3.110073483,1.781539638],
        [1.343808831,3.368360954],
        [3.582294042,4.679179110],
        [2.280362439,2.866990263],
        [7.423436942,4.696522875],
        [5.745051997,3.533989803],
        [9.172168622,2.511101045],
        [7.792783481,3.424088941],
        [7.939820817,0.791637231],
    ]
    raw_data_y = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
    
    # 转化为numpy数组
    X = np.array( raw_data_X )
    y = np.array( raw_data_y )
    # 待确定的样本
    x = np.array( [ 8.093607318, 3.365731514 ] ).reshape( 1, -1 )
    
    knn_clf = KNNClassifier( k = 6 )
    knn_clf.fit( X, y )
    y_predict = knn_clf.predict( x )
    print( y_predict )  # [1]
